#include "util/z9_string.h"
#include "util/z9_util.h"
#include "util/z9_error.h"
#include <stdlib.h>

z9_string *z9_string_new(const char *ptr,size_t len) {
	size_t cap;
	z9_string *str = (z9_string*)calloc(1,sizeof(*str));
	if(!str) return NULL;
	str->ptr = str->buff;
	if(ptr && len > 0) {
		str->len = len;
		cap = z9_size_of_pow2(len+1);
		if(cap > Z9_STRING_INIT_SIZE) {
			str->ptr = (char*)calloc(1,cap);
			if(!str->ptr) {
				free(str->ptr);
				str = NULL;
			}
		}
		str->cap = cap > Z9_STRING_INIT_SIZE ? cap : Z9_STRING_INIT_SIZE;
		memcpy(str->ptr,ptr,len);
		str->ptr[len] = 0;		
	}
	return str;
}

z9_string *z9_string_new_cstr(const char *ptr) {
	return z9_string_new(ptr,strlen(ptr));
}

void z9_string_destroy(z9_string *str) {
	if(str->ptr != str->buff)
		free(str->ptr);
	free(str);
}

int32_t z9_string_append_cstr(z9_string *str,const char *ptr) {
	return z9_string_append(str,ptr,strlen(ptr));
}

int32_t z9_string_append(z9_string *str,const char *ptr,size_t len) {
	char  *tmp;
	size_t newlen,cap;
	if(!ptr || 0 >= len)
		return z9_error_invaild_argument;
	newlen = len + str->len;
	cap = z9_size_of_pow2(newlen+1);
	if(cap > Z9_STRING_INIT_SIZE) {
		if(str->ptr == str->buff)
			tmp = (char*)calloc(1,cap);
		else
			tmp = (char*)realloc(str->ptr,cap);
		if(!tmp) return z9_error_no_memory;
		str->ptr = tmp;		
	}
	memcpy(str->ptr + str->len,ptr,len);
	str->ptr[newlen] = 0;
	str->len = newlen;
	str->cap = cap > Z9_STRING_INIT_SIZE ? cap : Z9_STRING_INIT_SIZE;	
	return z9_error_ok;
}

size_t z9_string_size(z9_string *str) {
	return str->len;
}

int32_t z9_string_equal(z9_string *r,z9_string *l) {
	return strcmp(r->ptr,l->ptr);
}

const char *z9_string_c_str(z9_string *str) {
	return str->ptr;
}